package com.example.springboot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.springboot.common.Constants;
import com.example.springboot.common.Page;
import com.example.springboot.common.Result;
import com.example.springboot.dto.*;
import com.example.springboot.entity.*;
import com.example.springboot.exception.ServiceException;
import com.example.springboot.mapper.UserMapper;
import com.example.springboot.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springboot.utils.*;
import com.vdurmont.emoji.EmojiManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private IUserService userService;
    @Resource
    private ISolutionService solutionService;
    @Resource
    private ICreativeService creativeService;
    @Resource
    private IFollowService followService;
    @Resource
    private ISCommentService scommentService;
    @Resource
    private ISCollectionService scollectionService;
    @Resource
    private ICCommentService ccommentService;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public UserSolutionDTO getUserSolutionDTO(Integer id,Integer solutionId) {
        User userById = userService.getById(id);
        UserSolutionDTO result = new UserSolutionDTO();
        UserDTO userDTO = new UserDTO();

        userDTO.setId(id);
        userDTO.setNickname(userById.getNickname());
        userDTO.setProfilepic(userById.getProfilepic());
        result.setUserDTO(userDTO);

        result.setView(solutionService.getViewByUser(id));
        //设置recentSolutions
        List<Solution> solutionList = solutionService.findByUserId(id);
        solutionList.removeIf(solution -> !solution.getStatement().equals("已发布"));
        List<Solution> recentSolutions = solutionList;
        List<SolutionDTO> solutionDTOList = new ArrayList<>();
        boolean judge = false;
        if (solutionList.size() > 3) {
            for (Solution solution : solutionList.subList(0,3)) {
                if (solution.getId().equals(solutionId)) {
                    judge = true;
                    break;
                }
            }
            if (judge)
                recentSolutions = solutionList.subList(0,4);
            else
                recentSolutions = solutionList.subList(0,3);
        }
        for (Solution solution : recentSolutions) {
            if (!solution.getId().equals(solutionId)){
                SolutionDTO solutionDTO = new SolutionDTO();
                solutionDTO.setId(solution.getId());
                solutionDTO.setName(solution.getName());
                solutionDTO.setView(solution.getView());
                solutionDTOList.add(solutionDTO);
            }
        }
        result.setSolutionList(solutionDTOList);
        result.setSolutionCount(solutionList.size());
        result.setFanCount(followService.findFollower(id).size());

        //设置评论数、收藏数
        int solutionComments = 0;
        int solutionCollections = 0;
        for (Solution solution : solutionList) {
            solutionComments += scommentService.getCount(solution.getId());
            solutionCollections += scollectionService.getCount(solution.getId());
        }
        result.setCommentedCount(solutionComments);
        result.setCollectedCount(solutionCollections);
        return result;
    }

    @Override
    public UserDTO getUserDTO(Integer id) {
        User user = userService.getById(id);
        UserDTO userDTO = new UserDTO();
        if (user==null)
            return null;
        else {
            userDTO.setId(id);
            userDTO.setNickname(user.getNickname());
            userDTO.setProfilepic(user.getProfilepic());
            return userDTO;
        }
    }

    @Override   //个人主页信息
    public UserHomeDTO getHome(Integer id) {
        User user = userService.getById(id);
        UserHomeDTO userHomeDTO = new UserHomeDTO();
        userHomeDTO.setMine(id.equals(Objects.requireNonNull(TokenUtils.getCurrentUser()).getId()));
        UserDTO userDTO = new UserDTO();
        if (user == null)
            return null;
        else {
            userDTO.setId(user.getId());
            userDTO.setNickname(user.getNickname());
            userDTO.setProfilepic(user.getProfilepic());
            userHomeDTO.setUserDTO(userDTO);
            userHomeDTO.setSex(user.getSex());
            userHomeDTO.setEmail(user.getEmail());
            userHomeDTO.setAddress(user.getAddress());
            userHomeDTO.setOccupation(user.getOccupation());
            userHomeDTO.setIntroduction(user.getIntroduction());

            userHomeDTO.setCreativeHomeDTOS(creativeService.getCreativeHomes(id));
            userHomeDTO.setSolutionAllDTOS(solutionService.getSolutionHomes(id));
            return userHomeDTO;
        }
    }

    @Override   //个人中心评论管理
    public HashMap<String, List<CmntCenterDTO>> getCommentsCenter(Integer id) {
        HashMap<String,List<CmntCenterDTO>> result = new HashMap<>();
        //设置所有用户对我的创意的评论
        List<CmntCenterDTO> myCreative = getMyCreativeCmnts(id);

        //设置所有用户对我的方案的评论
        List<CmntCenterDTO> mySolution = getMySolutionCmnts(id);

        //设置我发布的对创意的评论
        List<CmntCenterDTO> toCreative = getToCreative(id);

        //设置我发布的对方案的评论
        List<CmntCenterDTO> toSolution = getToSolution(id);

        result.put("myCreative",myCreative);
        result.put("mySolution",mySolution);
        result.put("toCreative",toCreative);
        result.put("toSolution",toSolution);
        return result;
    }

    @Override   //管理员查找用户
    public Result findPage(int pageNum, int pageSize, String username, String nickname) {
        Page page = new Page();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username",username);
        queryWrapper.like("nickname",nickname);
        List<User> list = userService.list(queryWrapper);
        if(list.isEmpty()) {
            return Result.error(Constants.CODE_600,null);
        }
        return Result.success(page.startPage(list,pageNum,pageSize));
    }

    @Override   //根据邮箱验证码验证登录
    public Result loginByCode(String email, String code, HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return Result.error(Constants.CODE_600,"验证码未发送");
        }
        String Email = (String) session.getAttribute("email");
        String Code = (String) session.getAttribute("code");
        Date start = (Date) session.getAttribute("time");
        //判断该邮箱是否注册
        User user = getByEmail(email);
        if (user == null) {
            return Result.error(Constants.CODE_600,"该邮箱未注册");
        }
        //判断获取验证码的邮箱与登录的邮箱是否一致
        if (!email.equals(Email)) {
            return Result.error(Constants.CODE_600,"验证码错误");
        }
        //判断验证码是否过期
        double diff = (double) (new Date().getTime() - start.getTime()) / 1000;
        if (diff > 180) {
            return Result.error(Constants.CODE_600,"验证码已过期");
        }
        if (code.equals(Code)) {
            LoginDTO loginDTO = new LoginDTO();
            BeanUtil.copyProperties(user,loginDTO,true);
            loginDTO.setToken(TokenUtils.genToken(user.getUsername(),user.getEmail()));
            return Result.success("验证码正确",loginDTO);
        }
        return Result.error(Constants.CODE_600,"验证码错误");
    }

    @Override   //根据密码登录
    public Result loginByPassword(String email, String password) {
        User user = getByEmail(email);
        if (user == null)
            return Result.error(Constants.CODE_600,"该邮箱未注册");
        if (user.getPassword() == null)
            return Result.error(Constants.CODE_600,"邮箱或密码错误");
        if (!PasswordEncoder.matches(password,user.getPassword()))
            return Result.error(Constants.CODE_600,"邮箱或密码错误");
        LoginDTO loginDTO = new LoginDTO();
        BeanUtil.copyProperties(user,loginDTO,true);
        loginDTO.setToken(TokenUtils.genToken(user.getUsername(),user.getEmail()));
        return Result.success(loginDTO);
    }

    @Override   //第一次第三方登录
    public Result firstLoginFromPlatform(String email, String username, String code,HttpServletRequest request) throws IOException {
        User user = getByEmail(email);
        if (user != null)
            return Result.error(Constants.CODE_600,"该邮箱已注册");
        HttpSession session = request.getSession(false);
        if (session == null) {
            return Result.error(Constants.CODE_600,"验证码未发送");
        }
        String Email = (String) session.getAttribute("email");
        String Code = (String) session.getAttribute("code");
        Date start = (Date) session.getAttribute("time");
        //判断获取验证码的邮箱与登录的邮箱是否一致
        if (!email.equals(Email)) {
            return Result.error(Constants.CODE_600,"验证码错误");
        }
        //判断验证码是否过期
        double diff = (double) (new Date().getTime() - start.getTime()) / 1000;
        if (diff > 180) {
            return Result.error(Constants.CODE_600,"验证码已过期");
        }
        if (code.equals(Code)) {
            User user1 = new User();
            user1.setUsername("platform_" + username);
            user1.setEmail(email);
            user1.setNickname(SensitiveWordUtil.sensitiveHelper(username));
            save(user1);
            LoginDTO loginDTO = new LoginDTO();
            BeanUtil.copyProperties(user1,loginDTO,true);
            loginDTO.setToken(TokenUtils.genToken("platform_" + username,email));
            return Result.success(loginDTO);
        }
        return Result.error(Constants.CODE_600,"验证码错误");
    }

    @Override   //非第一次第三方登录
    public Result loginFromPlatform(String email, String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        queryWrapper.eq("username",username);
        User user;
        try {
            user = userService.getOne(queryWrapper);
        } catch (Exception e) {
            throw new ServiceException(Constants.CODE_500, "系统错误");
        }
        if (user == null)
            return Result.error(Constants.CODE_500, "系统错误");
        LoginDTO loginDTO = new LoginDTO();
        BeanUtil.copyProperties(user,loginDTO,true);
        loginDTO.setToken(TokenUtils.genToken(username,email));
        return Result.success(loginDTO);
    }

    @Override   //用户设置密码
    public Result setPassword(String email, String code, String password, HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return Result.error(Constants.CODE_600,"验证码未发送");
        }
        String Email = (String) session.getAttribute("email");
        String Code = (String) session.getAttribute("code");
        Date start = (Date) session.getAttribute("time");
        //判断获取验证码的邮箱与登录的邮箱是否一致
        if (!email.equals(Email)) {
            return Result.error(Constants.CODE_600,"验证码错误");
        }
        //判断验证码是否过期
        double diff = (double) (new Date().getTime() - start.getTime()) / 1000;
        if (diff > 180) {
            return Result.error(Constants.CODE_600,"验证码已过期");
        }
        if (getByEmail(email) == null) {
            return Result.error(Constants.CODE_600,"系统错误");
        }
        if (code.equals(Code)) {
            User user = new User();
            user.setPassword(PasswordEncoder.encode(password));
            user.setId(Objects.requireNonNull(TokenUtils.getCurrentUser()).getId());
            if (saveOrUpdate(user))
                return Result.success("设置成功");
            else
                return Result.error(Constants.CODE_600,"系统错误");
        }
        return Result.error(Constants.CODE_600,"验证码错误");
    }

    @Override   //注册
    public Result register(LoginDTO loginDTO, HttpServletRequest request) throws IOException {
        if (StrUtil.isBlank(loginDTO.getUsername()) || StrUtil.isBlank(loginDTO.getNickname())) {
            return Result.error(Constants.CODE_600,"用户名不能为空");
        }
        if (!SensitiveWordUtil.sensitiveHelper(loginDTO.getUsername()).equals(loginDTO.getUsername()))
            throw new ServiceException(Constants.CODE_600,"用户名含敏感词汇，请重新输入");
        if (EmojiManager.containsEmoji(loginDTO.getUsername()) || EmojiManager.containsEmoji(loginDTO.getPassword()))
            throw new ServiceException(Constants.CODE_600,"用户名或密码含特殊字符");
        if (StrUtil.isBlank(loginDTO.getEmail())) {
            return Result.error(Constants.CODE_600,"邮箱不能为空");
        }
        if (getByName(loginDTO.getUsername()) != null) {
            return Result.error(Constants.CODE_600,"该用户名已注册");
        }
        if (getByEmail(loginDTO.getEmail()) != null) {
            return Result.error(Constants.CODE_600,"该邮箱已注册");
        }
        HttpSession session = request.getSession(false);
        if (session == null) {
            return Result.error(Constants.CODE_600,"验证码未发送");
        }
        String Email = (String) session.getAttribute("email");
        String Code = (String) session.getAttribute("code");
        Date start = (Date) session.getAttribute("time");
        //判断获取验证码的邮箱与登录的邮箱是否一致
        if (!loginDTO.getEmail().equals(Email)) {
            return Result.error(Constants.CODE_600,"验证码错误");
        }
        //判断验证码是否过期
        double diff = (double) (new Date().getTime() - start.getTime()) / 1000;
        if (diff > 180) {
            return Result.error(Constants.CODE_600,"验证码已过期");
        }
        if (loginDTO.getCode().equals(Code)) {
            loginDTO.setRole("ROLE_USER");
            User user = new User();
            BeanUtil.copyProperties(loginDTO,user,true);
            user.setPassword(PasswordEncoder.encode(loginDTO.getPassword()));
            if (userService.save(user))
                return Result.success("验证码正确,注册成功",user);
            return Result.error(Constants.CODE_600,"注册失败");
        }
        return Result.error(Constants.CODE_600,"验证码错误");
    }

    @Override   //用户修改头像，存到redis中等待管理员审核
    public String updateAvatar(String url) {
        Integer userId = Objects.requireNonNull(TokenUtils.getCurrentUser()).getId();
        HashMap<String,Object> hashMap = new HashMap<>();
        hashMap.put("userId", userId);
        hashMap.put("url",url);
        redisUtil.hmset(Constants.User_Avatar_KEY + ":" + userId,hashMap);
        return "上传成功，审核中";
    }

    @Override   //管理员通过头像审核
    public Result publishAvatar(Integer id, String url) {
        Map<Object, Object> map;
        map = redisUtil.hmget(Constants.User_Avatar_KEY + ":" + id);
        if (map.size() == 0)
            throw new ServiceException(Constants.CODE_600,"未找到该头像");
        String urlInRedis = (String) map.get("url");
        if (!url.equals(urlInRedis))
            return Result.error(Constants.CODE_600,"用户已重新上传头像");
        User user = new User();
        user.setId(id);
        user.setProfilepic(url);
        if (saveOrUpdate(user)) {
            redisUtil.del(Constants.User_Avatar_KEY + ":" + id);
            return Result.success("发布成功");
        }
        return Result.error(Constants.CODE_600,"发布失败");
    }

    @Override   //管理员打回待审核头像
    public Result unPublishAvatar(Integer id, String url) {
        Map<Object, Object> map;
        map = redisUtil.hmget(Constants.User_Avatar_KEY + ":" + id);
        if (map.size() == 0)
            throw new ServiceException(Constants.CODE_600,"未找到该头像");
        String urlInRedis = (String) map.get("url");
        if (!url.equals(urlInRedis))
            return Result.error(Constants.CODE_600,"用户已重新上传头像");
        redisUtil.del(Constants.User_Avatar_KEY + ":" + id);
        return Result.success("删除成功");
    }

    @Override   //管理员获取待审核头像的用户列表
    public Page getAvatars(int PageNum, int PageSize) {
        Set<String> keys = redisUtil.keys(Constants.User_Avatar_KEY + ":*");
        List<UserDTO> userDTOS = new ArrayList<>();
        for (String key : keys) {
            Map<Object,Object> map = redisUtil.hmget(key);
            Integer userId = (Integer) map.get("userId");
            String url = (String) map.get("url");
            User user = userService.getById(userId);
            if (user == null)
                throw new ServiceException(Constants.CODE_600,"未找到用户");
            UserDTO userDTO = new UserDTO();
            user.setProfilepic(url);
            BeanUtil.copyProperties(user,userDTO,true);
            userDTOS.add(userDTO);
        }
        Page page = new Page();
        return page.startPage(userDTOS,PageNum,PageSize);
    }

    @Override   //获取传入token对应用户的用户名、昵称、头像
    public User getByToken(String token) {
        if (StrUtil.isBlank(token)) {
            throw new ServiceException(Constants.CODE_600, "无token，请重新登录");
        }
        String username;
        try {
            username = JWT.decode(token).getClaim("username").asString();
        } catch (JWTDecodeException j) {
            throw new ServiceException(Constants.CODE_600, "token验证失败，请重新登录");
        }
        if (username == null)
            throw new ServiceException(Constants.CODE_600, "token验证失败，请重新登录");
        User user = getByName("platform_" + username);
        if (user == null) {
            User result = new User();
            result.setUsername(username);
            return result;
        }
        return user;
    }

    //根据username查找用户
    private User getByName(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        User one;
        try {
            one = userService.getOne(queryWrapper); // 从数据库查询用户信息
        } catch (Exception e) {
            throw new ServiceException(Constants.CODE_500, "系统错误");
        }
        return one;
    }

    //根据邮箱查找用户
    public User getByEmail(String email) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        User one;
        try {
            one = userService.getOne(queryWrapper);
        } catch (Exception e) {
            throw new ServiceException(Constants.CODE_500, "系统错误");
        }
        return one;
    }

    //获取用户发布创意下面的评论
    private List<CmntCenterDTO> getMyCreativeCmnts(Integer id) {
        //设置我发布的创意的评论
        List<CmntCenterDTO> myCreative = new ArrayList<>();
        for (Creative creative : creativeService.getByUser(id)) {
            QueryWrapper<CComment> commentQueryWrapper = new QueryWrapper<>();
            commentQueryWrapper.eq("creative_id",creative.getId());
            List<CComment> commentList = ccommentService.list(commentQueryWrapper);
            for (CComment cComment : commentList) {
                CmntCenterDTO cmntCenterDTO = new CmntCenterDTO();
                cmntCenterDTO.setName(creative.getName());
                cmntCenterDTO.setArticleId(creative.getId());
                cmntCenterDTO.setId(cComment.getId());
                cmntCenterDTO.setPid(cComment.getPid());
                cmntCenterDTO.setOriginId(cComment.getOriginId());
                UserDTO userDTO = getUserDTO(cComment.getUserId());
                if (userDTO == null)
                    continue;
                cmntCenterDTO.setUserDTO(userDTO);
                cmntCenterDTO.setContent(cComment.getContent());
                cmntCenterDTO.setCreateTime(cComment.getCreateTime());
                cmntCenterDTO.setRelativeTime(TimeUtil.createRelative(cComment.getCreateTime()));
                myCreative.add(cmntCenterDTO);
            }
        }
        myCreative.sort(Comparator.comparing(CmntCenterDTO::getCreateTime).reversed());
        return myCreative;
    }

    //获取用户发布方案下面的评论,用户中心
    private List<CmntCenterDTO> getMySolutionCmnts(Integer id) {
        //设置我发布的方案的评论
        List<CmntCenterDTO> mySolution = new ArrayList<>();
        for (Solution solution : solutionService.findByUserId(id)) {
            QueryWrapper<SComment> sCommentQueryWrapper = new QueryWrapper<>();
            sCommentQueryWrapper.eq("solution_id",solution.getId());
            List<SComment> sCommentList = scommentService.list(sCommentQueryWrapper);
            for (SComment sComment : sCommentList) {
                CmntCenterDTO cmntCenterDTO = new CmntCenterDTO();
                cmntCenterDTO.setName(solution.getName());
                cmntCenterDTO.setArticleId(solution.getId());
                cmntCenterDTO.setId(sComment.getId());
                cmntCenterDTO.setPid(sComment.getPid());
                cmntCenterDTO.setOriginId(sComment.getOriginId());
                UserDTO userDTO = getUserDTO(sComment.getUserId());
                if (userDTO == null)
                    continue;
                cmntCenterDTO.setUserDTO(userDTO);
                cmntCenterDTO.setContent(sComment.getContent());
                cmntCenterDTO.setCreateTime(sComment.getCreateTime());
                cmntCenterDTO.setRelativeTime(TimeUtil.createRelative(sComment.getCreateTime()));
                mySolution.add(cmntCenterDTO);
            }
        }
        mySolution.sort(Comparator.comparing(CmntCenterDTO::getCreateTime).reversed());
        return mySolution;
    }

    //获取个人中心中 我对创意发布的评论
    private List<CmntCenterDTO> getToCreative(Integer id) {
        List<CmntCenterDTO> toCreative = new ArrayList<>();
        QueryWrapper<CComment> commentQueryWrapper = new QueryWrapper<>();
        commentQueryWrapper.eq("user_id",id);
        for (CComment cComment : ccommentService.list(commentQueryWrapper)) {
            CmntCenterDTO cmntCenterDTO = new CmntCenterDTO();
            cmntCenterDTO.setUserDTO(getUserDTO(id));
            cmntCenterDTO.setContent(cComment.getContent());
            cmntCenterDTO.setCreateTime(cComment.getCreateTime());
            cmntCenterDTO.setArticleId(cComment.getCreativeId());
            cmntCenterDTO.setId(cComment.getId());
            cmntCenterDTO.setPid(cComment.getPid());
            cmntCenterDTO.setOriginId(cComment.getOriginId());
            cmntCenterDTO.setName(creativeService.getById(cComment.getCreativeId()).getName());
            cmntCenterDTO.setRelativeTime(TimeUtil.createRelative(cComment.getCreateTime()));
            toCreative.add(cmntCenterDTO);
        }
        toCreative.sort(Comparator.comparing(CmntCenterDTO::getCreateTime).reversed());
        return toCreative;
    }

    //获取个人中心中 我对方案发布的评论
    private List<CmntCenterDTO> getToSolution(Integer id) {
        List<CmntCenterDTO> toSolution = new ArrayList<>();
        QueryWrapper<SComment> commentQueryWrapper = new QueryWrapper<>();
        commentQueryWrapper.eq("user_id",id);
        for (SComment sComment : scommentService.list(commentQueryWrapper)) {
            CmntCenterDTO cmntCenterDTO = new CmntCenterDTO();
            cmntCenterDTO.setUserDTO(getUserDTO(id));
            cmntCenterDTO.setContent(sComment.getContent());
            cmntCenterDTO.setArticleId(sComment.getSolutionId());
            cmntCenterDTO.setId(sComment.getId());
            cmntCenterDTO.setPid(sComment.getPid());
            cmntCenterDTO.setOriginId(sComment.getOriginId());
            cmntCenterDTO.setCreateTime(sComment.getCreateTime());
            cmntCenterDTO.setRelativeTime(TimeUtil.createRelative(sComment.getCreateTime()));
            cmntCenterDTO.setName(solutionService.getById(sComment.getSolutionId()).getName());
            toSolution.add(cmntCenterDTO);
        }
        toSolution.sort(Comparator.comparing(CmntCenterDTO::getCreateTime).reversed());
        return toSolution;
    }
}
